<?php

/**
 * 应用程序
 *
 * @package lib
 * @subpackage core
 * @author 苏宁 <snsnsky@gmail.com>
 *
 * $Id$
 */

namespace lib\core;
use lib\plugins\page\APageFactory;
use lib\plugins\cache\Memcached;
use lib\plugins\Log;

class Application
{
    /**
     * 配置信息
     *
     * @var array
     * @access public
     */
    public $cfg;

    /**
     * 应用程序的名字
     *
     * @var string
     * @access public
     */
    public $name;

    /**
     * 模块名称
     *
     * @var string
     * @access public
     */
    public $module;

    /**
     * 动作名称,用于确定调用模块类中的哪个 do . $action 方法, 默认为 Default
     *
     * @var string
     * @access public
     */
    public $action;

    /**
     * application的对象池
     *
     * @var array
     * @access protected
     */
    protected $pool = [];

    /**
     * 构造函数
     *
     * @param string $name 应用程序名称
     */
    public function __construct($name = NULL)
    {
        global $cfg;
        $this->cfg = & $cfg;
        if ($name === NULL)
        {
            $name = basename($_SERVER['SCRIPT_FILENAME'], '.php');
            $p = strpos($name, '.');
            if ($p !== false)
            {
                $name = substr($name, 0, $p);
            }
        }

        $this->name = $name;
        $this->action = isset($_GET['do']) ? ucfirst($_GET['do']) : 'Default';
        $this->module = $this->action == 'Default' ? '' : '_' . strtolower($this->action);

        $this->pool['cache'] = [];
    }

    /**
     * 运行应用程序
     *
     * @param string $do 动作名称
     *
     * @return Application
     */
    public function run($do = NULL)
    {
        $do = $do ?: $this->action;
        if (class_exists($this->name))
        {
            $module = new $this->name($this);
            $action = 'do' . $do;
            if (method_exists($module, $action))
            {
                $module->$action();
            }
            else
            {
                show_404();
            }
        }
        else
        {
            exit("应用程序运行出错.文件 {$_SERVER['SCRIPT_FILENAME']} 中找不到类定义:{$this->name}(1002)");
        }

        if (defined('__ENV__') && __ENV__ != 'ONLINE' && DEBUG)
        {
            $this->_logProfile();
        }

        return $this;
    }

    /**
     * 返回application的page对象
     *
     * @param string $engine Page引擎, 默认按application.cfg.php中的$cfg['page']['engine']设置
     * @return APageFactory
     */
    public function page($engine = NULL)
    {
        if (!isset($this->pool['page']))
        {
            $default = defined('ADMIN_ENV') && ADMIN_ENV === true ?
                $this->cfg['page']['adminEngine'] :
                $this->cfg['page']['engine'];

            $this->pool['page'] = APageFactory::create($this, $engine ? $engine : $default);
        }
        $this->pool['page']->value('_api_host', autohost('http://'. CURRENT_API_HOST . '/'));
        return $this->pool['page'];
    }

    /**
     * 返回application的log对象
     *
     * @param string $path 日志路径,在未指定文件名时,将自动使用路径的最后一部分作为文件名
     * @param array|string $data 日志数据
     * @param string $sep 日志数据分割符
     * @return Log
     */
    public function log($path = "", $data = [], $sep = "\t")
    {
        if (!isset($this->pool['log']))
        {
            $this->pool['log'] = new Log($path, $data, $sep);
        }
        else
        {
            $this->pool['log']->reset();
        }
        return $this->pool['log'];
    }

    /**
     * 返回客户端IP
     *
     * @return string
     */
    public function ip()
    {
        static $ip = null;
        if (!is_null($ip)) {
            return $ip;
        }

        $x_forword_for = $_SERVER['HTTP_X_FORWARDED_FOR'];
        if (!empty($x_forword_for)) {
            $ip_arr = explode(',', $x_forword_for);

            foreach ($ip_arr as $ip) {
                $ip = trim($ip);
                if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
                    return $ip;
                }
            }
        }

        $real_ip = $_SERVER['HTTP_X_REAL_IP'];
        $ip = $_SERVER['REMOTE_ADDR'];
        if (filter_var($real_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
            return $real_ip;
//
//            if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE) === false)
//            {
//                $ip = $real_ip;
//            }
        }

        if (!preg_match('/[\d\.]{7,15}/', $ip)) {
            $ip = '0.0.0.0';
        }

        return $ip;
    }

    /**
     * 页面重定向
     *
     * @param string $url 重定向目标URL
     * @param int $mode 重定向模式, 值意义如下:
     *                         0 通过PHP的header()函数实现
     *                         1 通过JavaScript的Location实现
     *                         2 通过JavaScript的Location.replace实现
     * return void
     */
    public function redirect($url, $mode = 1)
    {
        switch ($mode)
        {
            case 1:
                echo '<script type="text/javascript">location="' . $url . '";</script>';
                break;
            case 2:
                echo '<script type="text/javascript">location.replace("' . $url . '");</script>';
                break;
            default:
                header('HTTP/1.1 301 Moved Permanently');
                header('Location: ' . $url);
                break;
        }
        exit;
    }

    /**
     * 获取跳转地址
     *
     * @param String $defualt 默认地址
     *
     * @return String referer 跳转地址
     */
    public function referer($defualt = '')
    {
        if (!isset($_GET['referer']) && !isset($_SERVER['HTTP_REFERER']))
        {
            return $defualt;
        }

        if (isset($_GET['referer']))
        {
            $referer = trim($_GET['referer']);
        }
        else if (isset($_SERVER['HTTP_REFERER']))
        {
            $referer = trim($_SERVER['HTTP_REFERER']);
        }

        if (empty($referer))
        {
            return $defualt;
        }
        else
        {
            return strip_tags($referer);
        }
    }

    /**
     * 记录性能日志
     */
    private function _logProfile()
    {
        // 运行时间操作0.5秒的记下来
        if (function_exists('xdebug_time_index'))
        {
            if (xdebug_time_index() > 0.5)
            {
                $log = $this->log('Profile/Time', $_SERVER['REQUEST_URI'], "\r\n");
                $log->write();
            }
        }
    }
}
